Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

11장. AI 응답을 데이터로 다루기

1. AI 답변은 문장이지만, 서비스에서는 데이터가 되어야 한다

AI는 기본적으로 자연어 답변을 잘 만든다.

예를 들어 고객 문의를 AI에게 분류해달라고 하면 다음처럼 답할 수 있다.

이 문의는 결제 관련 문의로 보입니다.
사용자가 하트를 충전했지만 서비스에 반영되지 않았다고 말하고 있으므로,
우선순위는 높음으로 처리하는 것이 좋습니다.

사람이 읽기에는 괜찮다.

하지만 서비스에서 이 답변을 바로 사용하기는 어렵다.

예를 들어 시스템은 이런 처리를 해야 할 수 있다.

- 문의 유형이 결제이면 결제 담당 큐로 이동
- 우선순위가 높음이면 상단에 표시
- 요약 내용은 상담 화면에 저장
- 처리 상태는 대기 상태로 등록

이런 처리를 하려면 AI 답변이 문장이 아니라 정해진 구조의 데이터여야 한다.

서비스 입장에서는 다음처럼 받는 것이 훨씬 좋다.

{
  "category": "payment",
  "priority": "high",
  "summary": "사용자가 하트를 충전했지만 서비스에 반영되지 않았다고 문의함"
}

이제 서버는 값을 바로 사용할 수 있다.

category가 payment이면 결제 담당 큐로 이동
priority가 high이면 우선순위 높음으로 표시
summary는 상담 화면에 저장

AI 응답을 데이터로 다룬다는 것은 이런 의미다.

AI가 만든 문장을 사람이 읽는 수준에서 끝내지 않고,
서비스 로직에서 사용할 수 있는 구조로 만드는 것이다.

구조화된 데이터는 정해진 형식을 가진 데이터다.
예를 들어 JSON처럼 필드 이름과 값이 정해져 있으면 프로그램에서 읽고 처리하기 쉽다.


2. 자유 텍스트 응답의 문제점

AI에게 아무 형식도 지정하지 않으면 자유롭게 답변한다.

예를 들어 다음 요청을 보자.

아래 고객 문의를 분류해줘.

고객 문의:
하트를 충전했는데 반영이 안 돼요.

AI는 다음처럼 답할 수 있다.

이 문의는 결제 관련 문의입니다.
하트 충전 후 반영되지 않았다는 내용이므로 우선순위는 높게 보는 것이 좋습니다.

또는 이렇게 답할 수도 있다.

분류: 결제
중요도: 높음
요약: 하트 충전 후 미반영

또는 이렇게 답할 수도 있다.

고객이 결제 후 재화가 반영되지 않았다고 문의하고 있으므로,
결제/충전 장애 유형으로 분류할 수 있습니다.

사람이 보면 모두 비슷한 의미다.

하지만 프로그램 입장에서는 모두 다른 형식이다.

서버가 이 답변에서 문의 유형과 우선순위를 꺼내려면 문자열을 분석해야 한다.

"결제 관련 문의"라는 표현을 찾아야 하나?
"분류: 결제"라는 패턴을 찾아야 하나?
"결제/충전 장애"도 결제로 봐야 하나?
"중요도: 높음"과 "우선순위는 높게"는 같은 의미인가?

이런 방식은 불안정하다.

AI 답변이 조금만 달라져도 파싱이 실패할 수 있다.

자유 텍스트 응답의 문제는 다음과 같다.

- 답변 형식이 매번 달라질 수 있다.
- 프로그램에서 값을 추출하기 어렵다.
- 조건문이 복잡해진다.
- 예외 처리가 많아진다.
- 잘못된 값을 저장할 수 있다.
- 자동화에 연결하기 어렵다.

자유 텍스트는 사람이 읽기에는 좋다.

하지만 서비스 로직에 연결하려면 구조화가 필요하다.


3. JSON으로 응답 받기

AI 응답을 데이터로 다루는 가장 일반적인 방법은 JSON 형식으로 받는 것이다.

JSON은 웹 서비스에서 데이터를 주고받을 때 자주 사용하는 형식이다.

예를 들어 고객 문의 분류 결과를 다음처럼 받을 수 있다.

{
  "category": "payment",
  "priority": "high",
  "summary": "하트 충전 후 서비스에 반영되지 않았다는 문의"
}

이제 서버는 각 필드를 쉽게 사용할 수 있다.

if (result.category === "payment") {
    assignToPaymentTeam();
}

if (result.priority === "high") {
    markAsHighPriority();
}

saveSummary(result.summary);

AI에게 JSON으로 응답하게 하려면 프롬프트에서 형식을 명확히 지정해야 한다.

아래 고객 문의를 분류해줘.

반드시 다음 JSON 형식으로만 응답해줘.

{
  "category": "payment | login | broadcast | refund | other",
  "priority": "low | medium | high",
  "summary": "문의 요약"
}

고객 문의:
하트를 충전했는데 반영이 안 돼요.

이렇게 요청하면 AI는 대체로 JSON 형식으로 답한다.

하지만 주의해야 한다.

AI가 항상 완벽한 JSON을 반환한다는 보장은 없다.

다음처럼 앞뒤에 설명을 붙일 수 있다.

아래는 분류 결과입니다.

{
  "category": "payment",
  "priority": "high",
  "summary": "하트 충전 후 반영되지 않음"
}

또는 허용하지 않은 값을 넣을 수도 있다.

{
  "category": "heart_charge",
  "priority": "urgent",
  "summary": "하트 충전 문제"
}

사람이 보기에는 이해되지만, 서버 입장에서는 문제가 된다.

categorypayment, login, broadcast, refund, other 중 하나여야 하는데 heart_charge가 들어왔다.
prioritylow, medium, high 중 하나여야 하는데 urgent가 들어왔다.

그래서 JSON 응답을 받을 때는 반드시 검증이 필요하다.

JSON은 JavaScript Object Notation의 약자다.
사람이 읽기 쉽고 프로그램이 처리하기 쉬운 데이터 형식이다.


4. 스키마를 정해야 한다

AI 응답을 안정적으로 데이터로 사용하려면 먼저 스키마를 정해야 한다.

스키마는 데이터가 가져야 할 구조와 규칙이다.

예를 들어 고객 문의 분류 결과의 스키마는 다음처럼 정의할 수 있다.

{
  "category": "payment | login | broadcast | refund | other",
  "priority": "low | medium | high",
  "summary": "string"
}

조금 더 설명하면 다음과 같다.

필드타입설명허용 값
categorystring문의 유형payment, login, broadcast, refund, other
prioritystring처리 우선순위low, medium, high
summarystring문의 요약300자 이내 문자열

이렇게 스키마를 정하면 AI에게 요청할 때도 명확해지고, 서버에서 검증하기도 쉬워진다.

스키마가 없으면 AI와 서버가 서로 다른 기대를 하게 된다.

예를 들어 AI는 category에 “결제 문의”라고 넣을 수 있다.

{
  "category": "결제 문의",
  "priority": "높음",
  "summary": "하트 충전 후 반영되지 않음"
}

하지만 서버는 payment라는 값을 기대하고 있을 수 있다.

if (result.category === "payment") {
    assignToPaymentTeam();
}

이 경우 조건이 동작하지 않는다.

그래서 AI에게는 사람이 보기 좋은 값보다, 시스템에서 사용할 값을 명확히 알려줘야 한다.

category는 반드시 아래 값 중 하나로만 응답해줘.

- payment
- login
- broadcast
- refund
- other

스키마는 AI 응답을 시스템과 연결하는 약속이다.

스키마는 데이터의 구조와 규칙을 정의한 것이다.
어떤 필드가 필요하고, 각 필드가 어떤 타입과 값을 가져야 하는지 정한다.


5. AI 응답은 반드시 검증해야 한다

AI에게 JSON 형식과 스키마를 알려줬다고 해서 끝이 아니다.

서버에서는 반드시 AI 응답을 검증해야 한다.

AI 응답도 외부 입력값처럼 봐야 한다.

사용자 입력값을 검증하듯이, AI 응답도 검증해야 한다.

검증 흐름은 다음과 같다.

AI 응답 수신
→ JSON 파싱
→ 필수 필드 확인
→ 타입 확인
→ 허용 값 확인
→ 길이 제한 확인
→ 민감 정보 포함 여부 확인
→ 통과하면 사용
→ 실패하면 재요청 또는 기본 처리

예를 들어 다음 응답을 받았다고 해보자.

{
  "category": "payment",
  "priority": "high",
  "summary": "하트 충전 후 반영되지 않음"
}

서버는 다음을 확인해야 한다.

category가 존재하는가?
category가 허용된 값인가?
priority가 존재하는가?
priority가 low, medium, high 중 하나인가?
summary가 문자열인가?
summary가 너무 길지 않은가?
summary에 개인정보가 포함되어 있지 않은가?

간단한 검증 코드는 다음처럼 작성할 수 있다.

function validateInquiryClassification(result) {
    const allowedCategories = ["payment", "login", "broadcast", "refund", "other"];
    const allowedPriorities = ["low", "medium", "high"];

    if (!allowedCategories.includes(result.category)) {
        throw new Error("Invalid category");
    }

    if (!allowedPriorities.includes(result.priority)) {
        throw new Error("Invalid priority");
    }

    if (typeof result.summary !== "string") {
        throw new Error("Invalid summary");
    }

    if (result.summary.length > 300) {
        throw new Error("Summary is too long");
    }

    return true;
}

운영 환경에서는 Zod, Joi, JSON Schema 같은 검증 도구를 사용할 수 있다.

중요한 것은 AI가 만든 결과를 그대로 믿지 않는 것이다.

AI 응답이 잘못되면 서비스 로직이 잘못 동작할 수 있다.

잘못된 분류값
→ 잘못된 담당 부서로 이동

잘못된 우선순위
→ 긴급 문의가 뒤로 밀림

너무 긴 요약
→ 화면 깨짐

개인정보 포함 요약
→ 로그나 화면에 민감 정보 노출

AI 응답은 반드시 검증 후 사용해야 한다.


6. 허용 값은 최대한 제한하는 것이 좋다

AI 응답을 데이터로 사용할 때는 가능한 값을 제한하는 것이 좋다.

예를 들어 문의 유형을 자유롭게 작성하게 하면 AI가 다양한 표현을 사용할 수 있다.

결제
결제 문의
충전
하트 충전
결제/충전
payment
billing

사람이 보면 비슷하지만, 시스템에서는 모두 다른 값이다.

그래서 AI에게 허용 값을 명확히 알려줘야 한다.

category는 반드시 아래 값 중 하나로만 응답해줘.

- payment
- login
- broadcast
- refund
- report
- other

우선순위도 마찬가지다.

priority는 반드시 아래 값 중 하나로만 응답해줘.

- low
- medium
- high

이렇게 제한하면 서버에서 처리하기 쉬워진다.

switch (result.priority) {
    case "high":
        notifyManager();
        break;
    case "medium":
        addToNormalQueue();
        break;
    case "low":
        addToLowPriorityQueue();
        break;
}

허용 값이 제한되어 있으면 통계도 만들기 쉽다.

payment 문의가 하루에 몇 건인가?
high 우선순위 문의가 몇 퍼센트인가?
방송 관련 문의가 늘고 있는가?

반대로 AI가 자유롭게 값을 만들게 하면 통계가 깨진다.

payment
Payment
결제
결제문의
하트충전
billing

이런 값들을 나중에 다시 정리해야 한다.

서비스 로직과 통계에 사용할 값은 반드시 정해진 값으로 제한하는 것이 좋다.


7. 사람이 읽을 값과 시스템 값은 분리한다

AI 응답을 설계할 때 사람이 읽을 값과 시스템에서 사용할 값을 분리하는 것이 좋다.

예를 들어 문의 유형을 사람이 볼 때는 “결제 문의”라고 표시하고 싶을 수 있다.

하지만 시스템에서는 payment라는 값을 사용하는 것이 좋다.

{
  "category": "payment",
  "categoryLabel": "결제 문의",
  "priority": "high",
  "priorityLabel": "높음",
  "summary": "하트 충전 후 반영되지 않았다는 문의"
}

이렇게 하면 시스템 처리와 화면 표시를 분리할 수 있다.

하지만 더 좋은 방식은 서버에서 label을 관리하는 것이다.

AI는 시스템 값만 반환한다.

{
  "category": "payment",
  "priority": "high",
  "summary": "하트 충전 후 반영되지 않았다는 문의"
}

서버나 프론트엔드에서 표시명을 매핑한다.

const categoryLabels = {
    payment: "결제 문의",
    login: "로그인 문의",
    broadcast: "방송 문의",
    refund: "환불 문의",
    other: "기타 문의"
};

const priorityLabels = {
    low: "낮음",
    medium: "보통",
    high: "높음"
};

이 방식이 더 안정적이다.

AI가 매번 “결제 문의”, “결제”, “충전 문의”처럼 다르게 표현할 위험이 줄어든다.

시스템 값은 코드와 통계에 사용하고, 표시 문구는 서비스에서 관리하는 것이 좋다.

AI 응답:
category = payment

서버 처리:
payment 담당 큐로 이동

화면 표시:
결제 문의

이렇게 분리하면 나중에 화면 문구를 바꾸더라도 AI 프롬프트를 바꿀 필요가 없다.


8. AI 응답을 저장할 때 함께 저장해야 할 것

AI가 만든 결과를 DB에 저장할 때는 결과값만 저장하면 부족할 수 있다.

예를 들어 고객 문의 요약 결과만 저장한다고 해보자.

{
  "summary": "하트 충전 후 반영되지 않았다는 문의"
}

나중에 문제가 생기면 확인하기 어렵다.

어떤 모델이 만든 요약인가?
어떤 프롬프트로 만들었는가?
언제 생성했는가?
입력 원문은 어떤 버전이었는가?
누가 생성했는가?
토큰은 얼마나 사용했는가?

AI 결과를 운영 데이터로 저장하려면 메타데이터도 함께 저장하는 것이 좋다.

저장하면 좋은 정보:
- AI 결과
- 사용한 모델명
- 프롬프트 버전
- 생성 시간
- 생성 요청자
- 입력 데이터 기준 시점
- 입력 토큰 수
- 출력 토큰 수
- 성공/실패 상태

예를 들어 테이블은 다음처럼 설계할 수 있다.

ai_generated_results
- id
- feature_name
- target_type
- target_id
- result_json
- model_name
- prompt_version
- input_tokens
- output_tokens
- created_by
- created_at

고객 문의 요약이라면 다음처럼 저장할 수 있다.

{
  "feature_name": "customer_inquiry_summary",
  "target_type": "customer_inquiry",
  "target_id": 12345,
  "result_json": {
    "summary": "하트 충전 후 반영되지 않았다는 문의"
  },
  "model_name": "example-ai-model",
  "prompt_version": "v1.2.0",
  "input_tokens": 1200,
  "output_tokens": 80,
  "created_by": "admin_100",
  "created_at": "2026-05-04T10:30:00+09:00"
}

이렇게 저장하면 나중에 추적이 가능하다.

요약 품질이 이상하다
→ 어떤 프롬프트 버전이었는지 확인
→ 어떤 모델이었는지 확인
→ 해당 버전으로 생성된 다른 결과도 검토

AI 결과도 서비스 데이터다.

따라서 생성 이력과 기준을 남겨야 한다.


9. AI 결과를 다시 생성할 수 있게 해야 한다

AI가 만든 결과는 항상 마음에 들지 않을 수 있다.

요약이 너무 짧을 수도 있고,
분류가 틀릴 수도 있고,
표현이 어색할 수도 있다.

그래서 AI 결과를 다시 생성하는 기능이 필요할 수 있다.

예를 들어 고객 문의 요약 화면에 다음 버튼을 둘 수 있다.

[AI 요약 다시 생성]

다시 생성할 때는 몇 가지를 고려해야 한다.

- 기존 결과를 덮어쓸 것인가?
- 이전 결과를 이력으로 남길 것인가?
- 누가 다시 생성했는지 기록할 것인가?
- 비용이 중복 발생한다는 것을 고려했는가?
- 같은 입력이면 같은 결과가 나오게 할 것인가?

가장 단순한 방식은 기존 결과를 덮어쓰는 것이다.

기존 요약
→ 다시 생성
→ 새 요약으로 교체

하지만 운영 관점에서는 이력을 남기는 것이 더 좋을 수 있다.

1차 요약:
2026-05-04 10:30 생성

2차 요약:
2026-05-04 10:35 관리자 재생성

현재 사용 중:
2차 요약

이렇게 하면 품질 문제를 추적할 수 있다.

AI 결과를 다시 생성할 때는 프롬프트나 모델이 달라졌을 수도 있다.

그래서 생성 이력을 남겨야 한다.

- 1차 생성: model-a, prompt v1
- 2차 생성: model-a, prompt v2
- 3차 생성: model-b, prompt v2

AI 결과는 고정된 정답이 아니다.

모델, 프롬프트, 입력 데이터에 따라 달라질 수 있다.

따라서 재생성 기능과 이력 관리를 함께 고려하는 것이 좋다.


10. AI 응답을 자동 처리할 때는 더 조심해야 한다

AI 응답을 단순히 화면에 보여주는 것과,
AI 응답을 기준으로 시스템이 자동 동작하는 것은 위험도가 다르다.

예를 들어 다음 두 기능은 위험도가 다르다.

낮은 위험:
AI가 고객 문의를 요약해서 상담원에게 보여준다.

높은 위험:
AI가 고객 문의를 분류하고 자동으로 환불 처리한다.

첫 번째는 사람이 확인한다.

AI가 조금 틀려도 상담원이 원문을 보고 판단할 수 있다.

두 번째는 AI 결과가 실제 시스템 작업으로 이어진다.

잘못 분류하면 환불이 잘못 처리될 수 있다.

AI 응답을 자동 처리에 사용할 때는 다음을 반드시 고려해야 한다.

- 잘못된 응답이 나왔을 때 피해가 큰가?
- 사람이 검토하는 단계가 있는가?
- 되돌릴 수 있는 작업인가?
- 로그와 감사 추적이 남는가?
- 권한 검사가 되어 있는가?
- AI 응답의 신뢰도를 평가할 수 있는가?

AI 응답을 기준으로 자동 처리해도 되는 작업은 보통 위험이 낮은 작업이다.

자동 처리 가능성이 높은 작업:
- 문의 태그 추천
- 낮은 위험의 카테고리 분류
- 요약 결과 저장
- 내부 검색 키워드 생성
- 임시 초안 생성

반대로 다음 작업은 자동 처리하면 위험하다.

자동 처리에 신중해야 하는 작업:
- 환불 승인
- 계정 정지
- 결제 취소
- 개인정보 변경
- 권한 부여
- 고객에게 공식 답변 발송

이런 작업은 AI가 제안하고 사람이 승인하는 구조가 안전하다.

AI 판단
→ 담당자 검토
→ 승인
→ 시스템 반영

AI 응답을 데이터로 다루는 것은 강력하지만,
그 데이터가 자동 실행으로 이어질수록 검증과 승인 절차가 중요해진다.


11. AI 응답에 신뢰도 값을 포함할 수 있을까

AI에게 결과와 함께 신뢰도 값을 달라고 요청할 수 있다.

예를 들어 다음처럼 응답을 받을 수 있다.

{
  "category": "payment",
  "confidence": 0.82,
  "summary": "하트 충전 후 반영되지 않았다는 문의"
}

confidence는 AI가 얼마나 확신하는지 나타내는 값처럼 보인다.

하지만 주의해야 한다.

LLM이 직접 생성한 confidence 값은 실제 확률이 아닐 수 있다.

AI가 “0.82”라고 답했다고 해서 정말 82% 확률로 맞다는 의미는 아니다.

그 값도 AI가 생성한 텍스트의 일부다.

그래서 confidence를 절대적인 기준으로 사용하면 위험하다.

위험한 사용:
confidence가 0.8 이상이면 자동 환불 처리

더 안전한 사용:
confidence가 낮으면 사람 검토 대상으로 표시

즉, confidence는 참고용으로만 사용하는 것이 좋다.

더 안정적인 방식은 규칙을 함께 사용하는 것이다.

예를 들어 문의 분류에서 AI가 애매한 경우를 표시하게 할 수 있다.

{
  "category": "payment",
  "needsReview": true,
  "reason": "결제 승인 여부와 충전 반영 여부를 추가 확인해야 함",
  "summary": "하트 충전 후 반영되지 않았다는 문의"
}

이 방식이 더 실무적이다.

AI가 숫자 확률을 만들게 하기보다,
검토 필요 여부와 이유를 명확히 받는 것이다.

좋은 구조:
- category
- summary
- needsReview
- reviewReason

예시는 다음과 같다.

{
  "category": "payment",
  "summary": "하트 충전 후 서비스에 반영되지 않았다는 문의",
  "needsReview": true,
  "reviewReason": "결제 승인 여부와 충전 처리 로그 확인이 필요함"
}

AI의 신뢰도 숫자보다 중요한 것은
왜 검토가 필요한지 설명하는 것이다.


12. AI 응답을 화면에 표시할 때의 주의점

AI 응답을 데이터로 저장하거나 처리하는 것뿐 아니라,
화면에 어떻게 표시할지도 중요하다.

AI 결과는 일반 데이터와 구분해서 보여주는 것이 좋다.

예를 들어 상담 화면에서 AI 요약을 보여준다고 해보자.

[AI 요약]
고객은 하트 충전 후 서비스에 반영되지 않았다고 문의했습니다.

※ AI 요약은 참고용입니다. 처리 전 원문을 확인해주세요.

이렇게 표시하면 사용자는 AI 결과가 보조 정보라는 것을 알 수 있다.

만약 AI 요약을 원문처럼 보여주면 상담원이 AI 결과를 사실로 오해할 수 있다.

AI가 만든 분류값도 마찬가지다.

문의 유형: 결제
우선순위: 높음
AI 판단: 검토 필요
사유: 결제 승인 여부 확인 필요

이렇게 표시하면 담당자가 AI 판단을 참고하되, 최종 확인을 할 수 있다.

AI 결과 UI에서 고려할 항목은 다음과 같다.

- AI가 생성한 결과임을 표시하는가?
- 원문을 함께 볼 수 있는가?
- 사람이 수정할 수 있는가?
- 다시 생성할 수 있는가?
- 검토 필요 여부가 표시되는가?
- 생성 시간과 생성자를 볼 수 있는가?
- 어떤 기준으로 분류되었는지 설명이 있는가?

AI 결과를 사용자에게 직접 보여주는 경우에는 더 신중해야 한다.

고객이 보는 화면에서는 AI가 만든 내용이 공식 안내처럼 보일 수 있다.

따라서 확정되지 않은 내용은 단정적으로 표시하지 않는 것이 좋다.

위험한 표현:
환불 가능합니다.

더 안전한 표현:
환불 가능 여부는 결제 상태와 이용 내역 확인 후 안내 가능합니다.

AI 결과를 데이터로 다루더라도,
그 데이터가 화면에서 어떻게 해석되는지까지 고려해야 한다.


13. 프롬프트 버전 관리가 필요한 이유

AI 응답 품질은 프롬프트에 크게 영향을 받는다.

프롬프트를 조금만 바꿔도 결과가 달라질 수 있다.

예를 들어 기존 프롬프트가 다음과 같았다고 하자.

고객 문의를 3줄로 요약해줘.

이후에 다음처럼 바꿨다.

고객 문의를 3줄로 요약해줘.

조건:
- 개인정보는 포함하지 마.
- 고객이 겪는 문제를 먼저 작성해.
- 상담원이 확인해야 할 내용을 마지막에 포함해.

이제 AI 결과는 이전과 달라질 수 있다.

그래서 운영에서는 프롬프트 버전을 관리하는 것이 좋다.

customer-summary v1.0
- 단순 3줄 요약

customer-summary v1.1
- 개인정보 제외 조건 추가

customer-summary v1.2
- 상담원 확인 사항 추가

AI 결과를 저장할 때 프롬프트 버전을 함께 저장하면 나중에 추적할 수 있다.

{
  "feature": "customer_summary",
  "promptVersion": "v1.2",
  "model": "example-ai-model",
  "result": {
    "summary": "하트 충전 후 반영되지 않았다는 문의"
  }
}

프롬프트 버전 관리는 다음 상황에서 중요하다.

- AI 결과 품질이 갑자기 달라졌을 때
- 특정 시점 이후 요약 방식이 바뀌었을 때
- 모델을 교체했을 때
- 장애나 고객 불만이 발생했을 때
- 이전 결과와 새 결과를 비교해야 할 때

프롬프트는 단순한 문장이 아니라 서비스 로직의 일부다.

따라서 코드처럼 버전 관리하고 변경 이력을 남기는 것이 좋다.


14. AI 응답을 테스트하는 방법

AI 응답을 서비스 데이터로 사용하려면 테스트가 필요하다.

일반 코드 테스트와 완전히 같지는 않지만, AI 기능도 기준 데이터를 만들어 평가할 수 있다.

예를 들어 고객 문의 분류 기능을 만든다면 테스트 샘플을 준비한다.

샘플 1:
하트를 충전했는데 반영이 안 돼요.
기대 category: payment

샘플 2:
비밀번호를 잊어버렸어요.
기대 category: login

샘플 3:
방송이 자꾸 끊겨요.
기대 category: broadcast

샘플 4:
결제 취소하고 싶어요.
기대 category: refund

AI 응답이 기대값과 맞는지 확인한다.

- category가 기대값과 맞는가?
- priority가 적절한가?
- summary가 원문 의미를 왜곡하지 않는가?
- 개인정보가 포함되지 않았는가?
- JSON 형식이 깨지지 않았는가?

테스트 샘플은 다양해야 한다.

- 짧은 문의
- 긴 문의
- 오타가 있는 문의
- 여러 이슈가 섞인 문의
- 욕설이 포함된 문의
- 개인정보가 포함된 문의
- 도메인 용어가 포함된 문의

AI 기능은 항상 100% 같은 결과를 보장하기 어려울 수 있다.

그래도 테스트 샘플을 만들면 프롬프트나 모델 변경 시 품질 비교가 가능하다.

기존 모델:
payment 분류 정확도 85%

새 모델:
payment 분류 정확도 92%
하지만 refund 분류 정확도 하락

이런 정보를 바탕으로 모델 변경 여부를 판단할 수 있다.

AI 응답을 데이터로 사용한다면,
반드시 평가 샘플과 테스트 기준을 만들어야 한다.


15. AI 응답 데이터 설계 예시: 고객 문의 분류

지금까지 내용을 바탕으로 고객 문의 분류 응답을 설계해보자.

목표는 다음과 같다.

고객 문의를 AI가 읽고,
문의 유형과 우선순위, 요약, 검토 필요 여부를 반환한다.

먼저 스키마를 정한다.

{
  "category": "payment | login | broadcast | refund | report | other",
  "priority": "low | medium | high",
  "summary": "string",
  "needsReview": "boolean",
  "reviewReason": "string"
}

각 필드의 의미는 다음과 같다.

필드설명
category문의 유형
priority처리 우선순위
summary상담원이 볼 요약
needsReview사람이 추가 검토해야 하는지
reviewReason검토가 필요한 이유

프롬프트는 다음처럼 작성할 수 있다.

아래 고객 문의를 분류해줘.

반드시 JSON 형식으로만 응답해줘.

스키마:
{
  "category": "payment | login | broadcast | refund | report | other",
  "priority": "low | medium | high",
  "summary": "300자 이내 요약",
  "needsReview": true 또는 false,
  "reviewReason": "검토가 필요한 이유. 없으면 빈 문자열"
}

규칙:
- category는 허용 값 중 하나만 사용해.
- priority는 고객 불편도와 처리 긴급도를 기준으로 판단해.
- summary에는 개인정보를 포함하지 마.
- 환불, 결제, 제재, 개인정보 변경과 관련된 내용은 needsReview를 true로 해.
- 확실하지 않으면 needsReview를 true로 해.

고객 문의:
{{message}}

예상 응답은 다음과 같다.

{
  "category": "payment",
  "priority": "high",
  "summary": "고객은 하트 충전 후 서비스에 반영되지 않았다고 문의했습니다.",
  "needsReview": true,
  "reviewReason": "결제 승인 여부와 충전 처리 로그 확인이 필요합니다."
}

서버에서는 이 응답을 검증한다.

- JSON 파싱 가능한가?
- category가 허용 값인가?
- priority가 허용 값인가?
- summary가 300자 이하인가?
- needsReview가 boolean인가?
- reviewReason이 문자열인가?

검증을 통과하면 저장한다.

문의 ID: 12345
AI 분류: payment
우선순위: high
요약: 고객은 하트 충전 후 서비스에 반영되지 않았다고 문의했습니다.
검토 필요: true
검토 사유: 결제 승인 여부와 충전 처리 로그 확인이 필요합니다.

이제 이 데이터는 서비스 로직에서 사용할 수 있다.

payment → 결제 담당 큐
high → 우선순위 상단 표시
needsReview true → 상담원 확인 배지 표시

이것이 AI 응답을 데이터로 다루는 방식이다.


16. AI 응답 데이터 설계 예시: 코드 리뷰 결과

이번에는 코드 리뷰 결과를 데이터로 받아보자.

AI 코드 리뷰를 PR 자동화에 연결하려면 자유 텍스트보다 구조화된 데이터가 좋다.

목표는 다음과 같다.

변경 코드를 AI가 검토하고,
문제 목록과 위험도, 개선 제안을 반환한다.

스키마 예시는 다음과 같다.

{
  "summary": "string",
  "riskLevel": "low | medium | high",
  "issues": [
    {
      "type": "bug | security | performance | maintainability | test | other",
      "severity": "low | medium | high",
      "file": "string",
      "line": "number 또는 null",
      "description": "string",
      "suggestion": "string"
    }
  ]
}

프롬프트는 다음처럼 작성할 수 있다.

아래 변경 코드를 리뷰해줘.

반드시 JSON 형식으로만 응답해줘.

스키마:
{
  "summary": "전체 리뷰 요약",
  "riskLevel": "low | medium | high",
  "issues": [
    {
      "type": "bug | security | performance | maintainability | test | other",
      "severity": "low | medium | high",
      "file": "문제가 있는 파일명. 모르면 빈 문자열",
      "line": "문제가 있는 라인 번호. 모르면 null",
      "description": "문제 설명",
      "suggestion": "개선 제안"
    }
  ]
}

조건:
- 실제 문제가 될 가능성이 높은 것만 포함해.
- 단순 코드 스타일 취향은 제외해.
- 보안 문제는 severity를 높게 평가해.
- 테스트가 필요한 부분은 type을 test로 표시해.

변경 코드:
{{diff}}

예상 응답은 다음과 같다.

{
  "summary": "로그인 실패 처리에서 계정 존재 여부 노출 가능성은 낮지만, rate limit이 없어 반복 시도에 취약할 수 있습니다.",
  "riskLevel": "medium",
  "issues": [
    {
      "type": "security",
      "severity": "medium",
      "file": "auth.controller.js",
      "line": 42,
      "description": "로그인 API에 요청 횟수 제한이 없어 무차별 대입 시도에 취약할 수 있습니다.",
      "suggestion": "사용자 또는 IP 기준 rate limit을 적용하는 것이 좋습니다."
    },
    {
      "type": "test",
      "severity": "low",
      "file": "auth.controller.js",
      "line": null,
      "description": "로그인 실패 횟수 제한과 관련된 테스트가 없습니다.",
      "suggestion": "반복 실패 시 제한되는 케이스를 테스트에 추가하세요."
    }
  ]
}

이 데이터를 활용하면 PR 댓글을 자동 생성할 수 있다.

전체 위험도: medium

1. [security] auth.controller.js:42
로그인 API에 요청 횟수 제한이 없어 무차별 대입 시도에 취약할 수 있습니다.
제안: 사용자 또는 IP 기준 rate limit을 적용하는 것이 좋습니다.

또 통계도 만들 수 있다.

이번 달 AI 리뷰에서 security 이슈가 몇 건 나왔는가?
테스트 누락 지적이 많은 프로젝트는 어디인가?
high severity 이슈가 얼마나 줄었는가?

AI 응답을 구조화하면 단순한 문장 답변을 넘어 자동화와 분석에 활용할 수 있다.


17. 구조화된 응답을 사용할 때의 한계

구조화된 AI 응답은 매우 유용하다.

하지만 한계도 있다.

첫 번째는 AI가 스키마를 항상 완벽히 지키지 않을 수 있다는 점이다.

- JSON 앞뒤에 설명을 붙일 수 있다.
- 허용되지 않은 값을 넣을 수 있다.
- 필드를 누락할 수 있다.
- 타입을 잘못 넣을 수 있다.

두 번째는 구조가 너무 복잡하면 오류가 늘어날 수 있다는 점이다.

필드가 많고 조건이 복잡할수록 AI가 실수할 가능성이 커진다.

좋은 스키마:
필드가 적고 명확하다.

나쁜 스키마:
필드가 너무 많고, 중첩이 깊고, 조건이 복잡하다.

세 번째는 구조화된 결과가 의미상 항상 맞는 것은 아니라는 점이다.

JSON 형식이 맞아도 판단이 틀릴 수 있다.

{
  "category": "login",
  "priority": "low",
  "summary": "하트 충전 문제"
}

형식은 맞지만 category가 잘못되었다.

그래서 검증은 두 단계로 나눠야 한다.

형식 검증:
JSON 구조, 필드, 타입, 허용 값 확인

의미 검증:
실제 내용과 분류 결과가 맞는지 확인

형식 검증은 코드로 자동화할 수 있다.

의미 검증은 샘플 테스트, 사람 검토, 운영 피드백을 통해 개선해야 한다.

AI 응답을 구조화한다고 해서 모든 문제가 해결되는 것은 아니다.

하지만 구조화하지 않으면 서비스 자동화가 훨씬 불안정해진다.


18. 정리

AI는 자연어 답변을 잘 만든다.

하지만 서비스에서 AI 결과를 사용하려면 자연어 문장만으로는 부족하다.

문의 분류, 우선순위 판단, 코드 리뷰, 문서 요약, 자동 태깅처럼
서비스 로직에 연결되는 기능은 AI 응답을 데이터로 다뤄야 한다.

AI 응답을 데이터로 다루려면 먼저 스키마를 정해야 한다.

어떤 필드가 필요한가?
각 필드는 어떤 타입인가?
허용되는 값은 무엇인가?
필수 값과 선택 값은 무엇인가?
길이 제한은 있는가?

그리고 AI에게 정해진 형식으로 응답하게 해야 한다.

하지만 AI가 항상 완벽히 지킨다고 믿으면 안 된다.

서버에서는 반드시 JSON 파싱, 필드 검증, 허용 값 검증, 길이 검증, 민감 정보 검사를 해야 한다.

AI 결과를 저장할 때는 결과값뿐 아니라 모델명, 프롬프트 버전, 생성 시간, 토큰 사용량도 함께 저장하는 것이 좋다.

AI 응답을 데이터로 잘 다루면 단순한 챗봇을 넘어 자동 분류, 업무 큐 이동, PR 리뷰 자동화, 운영 보조 기능으로 확장할 수 있다.

이 장에서 기억해야 할 핵심은 하나다.

AI 응답은 사람이 읽는 문장으로 끝나지 않는다.
서비스에 연결하려면 검증 가능한 데이터 구조로 다뤄야 한다.


11장 핵심 요약

핵심 내용설명
AI 답변은 데이터로 다뤄야 한다서비스 로직에 연결하려면 자연어 문장보다 구조화된 응답이 필요하다.
자유 텍스트는 자동화에 불안정하다답변 형식이 매번 달라질 수 있어 파싱과 후속 처리가 어렵다.
JSON 응답이 유용하다category, priority, summary처럼 필드를 나누면 서버에서 처리하기 쉽다.
스키마를 먼저 정해야 한다필드, 타입, 허용 값, 길이 제한을 명확히 정해야 한다.
AI 응답은 반드시 검증해야 한다JSON 파싱, 필수 필드, 타입, 허용 값, 길이, 민감 정보 포함 여부를 확인해야 한다.
허용 값은 제한하는 것이 좋다payment, login, refund처럼 정해진 값만 사용해야 통계와 로직이 안정적이다.
시스템 값과 표시 값은 분리한다AI는 payment 같은 시스템 값을 반환하고, 화면 표시명은 서비스에서 관리하는 것이 좋다.
AI 결과 저장 시 메타데이터도 필요하다모델명, 프롬프트 버전, 생성 시간, 토큰 사용량을 함께 저장해야 추적할 수 있다.
자동 처리에는 주의가 필요하다AI 결과가 환불, 제재, 권한 변경처럼 중요한 작업으로 이어지면 사람 검토가 필요하다.
구조화된 응답도 완벽하지 않다형식은 맞아도 의미가 틀릴 수 있으므로 샘플 테스트와 운영 피드백이 필요하다.